package service

import (
	"encoding/json"
	"github.com/pkg/errors"
	"github.com/spf13/cast"
	"nft-server/common"
	"nft-server/dao"
	"nft-server/db"
	"nft-server/logger"
	"nft-server/model"
	"nft-server/util"
	"strings"
	"time"
)

func GetCollectionDetailByUserIdAndCollection(userId int, collectionIndex string, subCollectionIndex int) (*model.CollectionDetail, error) {
	collection, err := dao.GetCollectionDetailDao().GetCollectionDetailByUserIdAndCollection(userId, collectionIndex, subCollectionIndex)
	if err != nil {
		return nil, errors.Errorf("GetCollectionDetailByUserIdAndCollection error: %v", err)
	}
	if err == nil && collection == nil {
		return nil, errors.Errorf("collection doesn't exist")
	}
	return collection, nil
}
func GetCollectionDetailByCollection(collectionIndex string, subCollectionIndex int) (*model.CollectionDetail, error) {
	return GetCollectionDetailByUserIdAndCollection(util.InvalidNumber, collectionIndex, subCollectionIndex)
}
func GetSubCollectionBySomeCollectionIndex(userId int, collectionIndex []string) (subCollections []*model.CollectionDetail, err error) {
	queryParameter := common.QueryCollectionDetail{
		CollectionIndex: collectionIndex,
	}
	if userId != util.InvalidNumber {
		queryParameter.UserId = &userId
	}
	subCollections, _, _, err = dao.GetCollectionDetailDao().GetCollection(&queryParameter)
	if err != nil {
		return nil, errors.Errorf("GetSubCollectionBySomeCollectionIndex error: %v", err)
	}
	return subCollections, nil
}
func GetSubCollectionByCollections(userId int, collections []*model.CollectionDetail) (subCollections []*model.CollectionDetail, err error) {
	var collectionIndex []string
	for _, oneCollection := range collections {
		collectionIndex = append(collectionIndex, oneCollection.CollectionIndex)
	}
	return GetSubCollectionBySomeCollectionIndex(userId, collectionIndex)
}
func GetCollectionDetailById(collectionIndex string, subCollectionIndex int) (*model.CollectionDetail, error) {
	collections, err := GetCollectionDetailByCollection(collectionIndex, subCollectionIndex)
	if err != nil {
		return nil, errors.Errorf("GetCollectionDetailById error: %v", err)
	}
	return collections, nil
}
func GetCollectionsByOneCollectionIndex(collectionIndex string) ([]*model.CollectionDetail, error) {
	collectionDetails, err := GetSubCollectionBySomeCollectionIndex(util.InvalidNumber, []string{collectionIndex})
	if err != nil {
		return nil, errors.Errorf("GetCollectionsByOneCollectionIndex error: %v", err)
	}
	return collectionDetails, nil
}

func CreateCollectionDetailInfo(userId int, collectionIndex string, req common.CollectionReq) *model.CollectionDetail {
	collectionDetail := new(model.CollectionDetail)
	collectionDetail.UserId = userId
	collectionDetail.CollectionIndex = collectionIndex
	collectionDetail.SubCollectionIndex = util.DefaultSubCollectionIndex
	collectionDetail.CollectionName = req.CollectionName
	collectionDetail.CollectionStatus = req.CollectionStatus
	collectionDetail.Supplies = util.DefaultSupplies
	collectionDetail.Counter = util.DefaultCounter
	collectionDetail.TokenId = util.DefaultTokenId
	collectionDetail.CreatedTime = time.Now()
	collectionDetail.SaleTime = util.GetDefaultTime()
	collectionDetail.OffShelfTime = util.GetDefaultTime()
	collectionDetail.NumberOfFavorites = util.DefaultFavorites
	collectionDetail.Issuer = util.DefaultIssuer
	collectionDetail.Price = util.DefaultPrice
	collectionDetail.CoverUrl = req.CoverUrl
	return collectionDetail
}

func CreateCollectionDetail(userId int, collectionIndex string, req common.CollectionReq) (*model.CollectionDetail, error) {
	collection := CreateCollectionDetailInfo(userId, collectionIndex, req)
	err := dao.GetCollectionDetailDao().SaveCollectionDetailInfo(collection)
	if err != nil {
		return nil, errors.Errorf("CreateCollectionDetail error: %v", err)
	}
	return collection, err
}
func SaveSubCollectionByMainCollection(collection *model.CollectionDetail, subCollectionIndex int, mintData common.MintReq) (*model.CollectionDetail, error) {
	subCollection := CreateSubCollectionByMainCollection(collection, subCollectionIndex, mintData)
	err := dao.GetCollectionDetailDao().SaveCollectionDetailInfo(subCollection)
	if err != nil {
		return nil, err
	}
	return subCollection, nil
}
func CreateSubCollectionByMainCollection(collection *model.CollectionDetail, subCollectionIndex int, mintData common.MintReq) *model.CollectionDetail {
	collectionDetail := new(model.CollectionDetail)
	collectionDetail.UserId = collection.UserId
	collectionDetail.CollectionIndex = collection.CollectionIndex
	collectionDetail.SubCollectionIndex = subCollectionIndex
	collectionDetail.CollectionName = collection.CollectionName
	collectionDetail.CollectionStatus = collection.CollectionStatus
	collectionDetail.Supplies = mintData.MintAmount
	collectionDetail.Counter = util.DefaultCounter
	collectionDetail.TokenId = util.DefaultTokenId
	collectionDetail.CreatedTime = time.Now()
	collectionDetail.SaleTime = util.GetDefaultTime()
	collectionDetail.OffShelfTime = util.GetDefaultTime()
	collectionDetail.NumberOfFavorites = util.DefaultFavorites
	collectionDetail.Issuer = mintData.Issuer
	collectionDetail.Price = util.DefaultPrice
	collectionDetail.CoverUrl = mintData.FileUrl
	return collectionDetail
}

func UpdateCollectionDetail(collectionDetail *model.CollectionDetail) error {
	err := dao.GetCollectionDetailDao().UpdateCollectionDetailInfo(collectionDetail)
	if err != nil {
		return errors.Errorf("UpdateCollectionDetailInfo error: %v", err)
	}
	return nil
}
func UpdateAllSubCollection(modifyParameter *common.ModifyCollectionDetail) error {
	err := dao.GetCollectionDetailDao().UpdateAllSubCollectionDetailInfo(modifyParameter)
	if err != nil {
		return errors.Errorf("UpdateCollectionTokenId error: %v", err)
	}
	return nil
}

func UpdateCollectionSupplies(userId int, collectionIndex string, subCollectionIndex, increaseSupplies int) error {
	collection, err := GetCollectionDetailByUserIdAndCollection(userId, collectionIndex, subCollectionIndex)
	if err != nil {
		return errors.Errorf("UpdateCollectionSupplies error: %v", err)
	}
	collection.Supplies += increaseSupplies
	err = dao.GetCollectionDetailDao().UpdateCollectionDetailInfo(collection)
	if err != nil {
		return errors.Errorf("UpdateCollectionSupplies error: %v", err)
	}
	return nil
}

func UpdateCollectionSuppliesAndDeleteWhenZero(userId int, collectionIndex string, subCollectionIndex, increaseSupplies int) error { //更新藏品supply，若剩余数量为0则删除
	collection, err := GetCollectionDetailByUserIdAndCollection(userId, collectionIndex, subCollectionIndex)
	if err != nil {
		return errors.Errorf("DeleteCollectionDetailInfo error: %v", err)
	}
	collection.Supplies += increaseSupplies
	if collection.Supplies <= 0 {
		err = dao.GetCollectionDetailDao().DeleteCollectionDetail(collection.Id)
		if err != nil {
			return errors.Errorf("DeleteCollectionDetailInfo error: %v", err)
		}

	} else {
		//supplies小于counter，证明已经销毁完
		if collection.Supplies <= collection.Counter && collection.CollectionStatus == util.CollectionBurning {
			collection.CollectionStatus = util.CollectionMintCompleted
		}
		err = dao.GetCollectionDetailDao().UpdateCollectionDetailInfo(collection)
		if err != nil {
			return errors.Errorf("UpdateCollectionDetailInfo error: %v", err)
		}
	}

	return nil
}

func UpdateCollectionStatusAndTokenId(userId int, collectionIndex string, subCollectionIndex int, collectionStatus, startTokenId *int) (err error) {
	//更新时,QueryOfSubCollectionIndex代表对全部子集合进行更新
	if subCollectionIndex == util.QueryOfSubCollectionIndex {
		err = dao.GetCollectionDetailDao().UpdateCollectionDetailStatusAndTokenId(userId, collectionIndex, collectionStatus, startTokenId)
	} else {
		collection, err := GetCollectionDetailByUserIdAndCollection(userId, collectionIndex, subCollectionIndex)
		if err != nil {
			return err
		}
		updateCollection := new(model.CollectionDetail)
		updateCollection.CollectionIndex = collection.CollectionIndex
		updateCollection.UserId = collection.UserId
		if collectionStatus != nil {
			updateCollection.CollectionStatus = *collectionStatus
		}
		if startTokenId != nil {
			updateCollection.TokenId = *startTokenId
		}
		err = dao.GetCollectionDetailDao().UpdateCollectionDetailInfo(updateCollection)
	}
	if err != nil {
		return errors.Errorf("UpdateCollectionStatus error: %v", err)
	}
	return nil
}
func UpdateCollectionCounter(userId int, collectionIndex string, subCollectionIndex, increaseCounter int) error {
	collection, err := GetCollectionDetailByUserIdAndCollection(userId, collectionIndex, subCollectionIndex)
	if err != nil {
		return errors.Errorf("UpdateCollectionDetailInfo error: %v", err)
	}
	collection.Counter += increaseCounter
	err = dao.GetCollectionDetailDao().UpdateCollectionDetailInfo(collection)
	if err != nil {
		return errors.Errorf("UpdateCollectionDetailInfo error: %v", err)
	}
	return nil
}

func GetNowTokenId(userId int, collectionIndex string, subCollectionIndex int) (tokenId int, err error) {
	collection, err := GetCollectionDetailByUserIdAndCollection(userId, collectionIndex, subCollectionIndex)
	if err != nil {
		return -1, errors.Errorf("GetNowTokenId error: %v", err)
	}
	return collection.TokenId, nil
}

func AddTokenId(userId int, collectionIndex string, subCollectionIndex, increaseNum int) error {
	collection, err := GetCollectionDetailByUserIdAndCollection(userId, collectionIndex, subCollectionIndex)
	if err != nil {
		return errors.Errorf("AddTokenId error: %v", err)
	}
	collection.TokenId += increaseNum
	err = dao.GetCollectionDetailDao().UpdateCollectionDetailInfo(collection)
	if err != nil {
		return errors.Errorf("AddTokenId error: %v", err)
	}
	return nil
}
func GetMainCollectionWithPage(userId int, page, pageSize int) (collections []*model.CollectionDetail, collectionSize, totalNum int, err error) {
	querySubCollectionIndex := util.DefaultSubCollectionIndex
	queryParameter := common.QueryCollectionDetail{
		SubCollectionIndex: &querySubCollectionIndex,
		Page:               &page,
		PageSize:           &pageSize,
	}
	if userId != util.InvalidNumber {
		queryParameter.UserId = &userId
	}
	return dao.GetCollectionDetailDao().GetCollection(&queryParameter)
}

func GetMainCollectionWithPageAndTime(collection *model.CollectionDetail, page, pageSize int, nowTime time.Time) (collections []*model.CollectionDetail, collectionSize, totalNum int, err error) {
	needDistinct := true
	queryParameter := common.QueryCollectionDetail{
		UserId:           &collection.UserId,
		CollectionName:   &collection.CollectionName,
		CollectionStatus: []int{collection.CollectionStatus},
		Page:             &page,
		PageSize:         &pageSize,
		NowTime:          &nowTime,
		Distinct:         &needDistinct,
	}
	collections, collectionSize, totalNum, err = dao.GetCollectionDetailDao().GetCollection(&queryParameter)
	if err != nil {
		return nil, -1, -1, errors.Errorf("GetMainCollectionIndexByPageAndTime error: %v", err)
	}
	return collections, collectionSize, totalNum, nil
}

//获取管理员创建的所有集合名字,参数中集合名和作者名以or连接，其他以and连接
func GetCollectionNamesForOrderQuery(collection *model.CollectionDetail) ([]*model.CollectionDetail, error) {
	needMainCollection := false
	queryParameter := common.QueryCollectionDetail{
		UserId:             &collection.UserId,
		NeedMainCollection: &needMainCollection,
		CollectionName:     &collection.CollectionName,
		Issuer:             &collection.Issuer,
		CollectionStatus:   []int{collection.CollectionStatus},
	}
	collections, _, _, err := dao.GetCollectionDetailDao().GetCollection(&queryParameter)
	if err != nil {
		return nil, errors.Errorf("GetCollectionNames error: %v", err)
	}
	return collections, nil
}

func GetCollectionNameForMint(userId int, collectionStatus int) ([]*model.CollectionDetail, error) {
	//只有管理员设置为不可见的集合才能被铸造
	subCollectionIndex := util.DefaultSubCollectionIndex

	queryParameter := common.QueryCollectionDetail{
		CollectionStatus:   []int{collectionStatus},
		SubCollectionIndex: &subCollectionIndex,
	}
	if userId != util.InvalidNumber {
		queryParameter.UserId = &userId
	}
	collections, _, _, err := dao.GetCollectionDetailDao().GetCollection(&queryParameter)
	if err != nil {
		return nil, errors.Errorf("GetCollectionNames error: %v", err)
	}
	return collections, nil
}
func GetCollectionForHomePage(userId int, collectionStatus int, nowTime time.Time, page, pageSize int) (collections []*model.CollectionDetail, collectionSize, totalNum int, err error) {
	needMainCollection := false
	queryParameter := common.QueryCollectionDetail{
		NeedMainCollection: &needMainCollection,
		Page:               &page,
		PageSize:           &pageSize,
	}
	if collectionStatus == util.DefaultCollectionStatus {
		collectionStatus = util.CollectionPublished
	} else {
		queryParameter.NowTime = &nowTime
	}
	queryParameter.CollectionStatus = []int{collectionStatus}
	if userId != util.InvalidNumber {
		queryParameter.UserId = &userId
	}

	return dao.GetCollectionDetailDao().GetCollection(&queryParameter)
}

func RebuildCollectionAndMetaData(response *common.CollectionDetailHomePage, collections []*model.CollectionDetail, size int, metadata []*model.MetaData, collectionStatus int) error {
	for i := 0; i < size; i++ {
		collectionDetail := common.CollectionDetailForHomePage{
			CollectionIndex:    collections[i].CollectionIndex,
			SubCollectionIndex: collections[i].SubCollectionIndex,
			Supplies:           collections[i].Supplies,
			Remain:             collections[i].Supplies - collections[i].Counter,
			CollectionName:     collections[i].CollectionName,
			CollectionStatus:   CheckCollectionStatus(collections[i]),
			Favorite:           collections[i].NumberOfFavorites,
			SaleTime:           collections[i].SaleTime.UnixMilli(),
			OffShelfTime:       collections[i].OffShelfTime.UnixMilli(),
			Currency:           collections[i].Currency,
			Price:              collections[i].Price,
			Issuer:             collections[i].Issuer,
		}
		if collectionDetail.CollectionStatus == util.CollectionInvisible {
			continue
		}
		detail := MetaDataDetail{}
		if err := json.Unmarshal([]byte(metadata[i].TokenURI), &detail); err != nil {
			return err
		}
		//获取web链接
		AssetUrl, err := GetAssetWebURl(detail.AssetUrl)
		collectionDetail.PictureName = detail.Name
		if err != nil {
			return err
		}
		collectionDetail.AssetUrl = AssetUrl
		collectionDetail.Description = detail.Description
		//根据集合状态筛选
		if collectionStatus != util.DefaultCollectionStatus && collectionStatus != collectionDetail.CollectionStatus {
			continue
		}
		response.Collection = append(response.Collection, collectionDetail)
	}
	return nil
}

func GetLastCollectionTimeWithStatus(userId int, collectionStatus []int, nowTime time.Time, num int) (collections []*model.CollectionDetail, collectionSize, totalNum int, err error) {
	return dao.GetCollectionDetailDao().GetLastCollectionByTime(userId, collectionStatus, nowTime, num)
}

func RebuildCollectionAndMetaDataForRecommend(response *common.CollectionDetailRecommend, collections []*model.CollectionDetail, size int, metadata []*model.MetaData) error {
	for i := 0; i < size; i++ {
		collectionDetail := common.CollectionDetailForRecommend{
			CollectionIndex:    collections[i].CollectionIndex,
			SubCollectionIndex: collections[i].SubCollectionIndex,
			Supplies:           collections[i].Supplies,
			Remain:             collections[i].Supplies - collections[i].Counter,
			CollectionName:     collections[i].CollectionName,
			CollectionStatus:   CheckCollectionStatus(collections[i]),
			Issuer:             collections[i].Issuer,
		}
		detail := MetaDataDetail{}
		if err := json.Unmarshal([]byte(metadata[i].TokenURI), &detail); err != nil {
			return err
		}
		//获取web链接
		AssetUrl, err := GetAssetWebURl(detail.AssetUrl)
		if err != nil {
			return err
		}
		detail.AssetUrl = AssetUrl
		collectionDetail.AssetUrl = detail.AssetUrl
		collectionDetail.Description = detail.Description
		collectionDetail.PictureName = detail.Name
		response.Collection = append(response.Collection, collectionDetail)
	}
	return nil
}
func GetMetaDataFromCollectionsInOrder(userId int, collectionSize int, collections []*model.CollectionDetail) ([]*model.MetaData, error) {
	collectionToMeta := make(map[common.CollectionIdentity]int)
	var queryCollectionIndex []string
	for _, oneCollection := range collections {
		queryCollectionIndex = append(queryCollectionIndex, oneCollection.CollectionIndex)
		collectionToMeta[common.CollectionIdentity{CollectionIndex: oneCollection.CollectionIndex, SubCollectionIndex: oneCollection.SubCollectionIndex}] = len(queryCollectionIndex) - 1
	}
	//获取子集合对应的meta
	metadata, _, err := GetMetaDataWithCollections(userId, queryCollectionIndex)
	if err != nil {
		logger.Error("GetMetaDataByCollections error: %v", err)
		return nil, err
	}
	queryMetadata := make([]*model.MetaData, collectionSize)
	for _, meta := range metadata {
		metaIdentity := common.CollectionIdentity{CollectionIndex: meta.CollectionIndex, SubCollectionIndex: meta.SubCollectionIndex}
		if _, ok := collectionToMeta[metaIdentity]; ok {
			queryMetadata[collectionToMeta[metaIdentity]] = meta
		}
	}
	return queryMetadata, nil
}

func BuildResponseForPublish(response *common.CollectionDetailPublishResponse, collectionIndex string, metaData *model.MetaData, collection *model.CollectionDetail) error {
	collectionInfo := common.CollectionDetailPublish{
		CollectionIndex:    collectionIndex,
		SubCollectionIndex: collection.SubCollectionIndex,
		Supplies:           collection.Supplies,
		CollectionName:     collection.CollectionName,
		Issuer:             collection.Issuer,
		SaleTime:           collection.SaleTime.UnixMilli(),
		OffShelfTime:       collection.OffShelfTime.UnixMilli(),
		Currency:           collection.Currency,
		Price:              collection.Price,
	}
	metaDetail := MetaDataDetail{}
	if err := json.Unmarshal([]byte(metaData.TokenURI), &metaDetail); err != nil {
		logger.Error("GetCollectionForPublish error: %v", err)
		return err
	}
	AssetUrl, err := GetAssetWebURl(metaDetail.AssetUrl)
	if err != nil {
		logger.Error("GetCollectionForPublish error: %v", err)
		return err
	}
	collectionInfo.Detail.AssetUrl = AssetUrl
	collectionInfo.Detail.Name = metaDetail.Name
	collectionInfo.Detail.Description = metaDetail.Description
	collectionInfo.Detail.Category = GetCategoryNameById(cast.ToInt(metaDetail.Category))
	response.CollectionsInfo = append(response.CollectionsInfo, collectionInfo)
	return nil
}

func CheckCollectionStatus(collection *model.CollectionDetail) int {
	collectionStatus := collection.CollectionStatus
	if collection.CollectionStatus == util.CollectionPublished {
		nowTime := time.Now()
		invisibleTime := collection.OffShelfTime.Add(util.OffShelfLiftTime)
		//已发布未出售
		if nowTime.Before(collection.SaleTime) {
			collectionStatus = util.CollectionPublished
		}
		//出售中
		if nowTime.After(collection.SaleTime) && nowTime.Before(collection.OffShelfTime) {
			collectionStatus = util.CollectionOnSale
		}
		//已结束
		if nowTime.After(collection.OffShelfTime) && nowTime.Before(invisibleTime) {
			collectionStatus = util.CollectionEnded
		}
		//已结束不可见
		if nowTime.After(invisibleTime) {
			collectionStatus = util.CollectionInvisible
		}
	}
	return collectionStatus
}

func CheckPrice(price float64) error {
	if price > 0 {
		ss := strings.Split(cast.ToString(price), ".")
		if len(ss[0]) < util.LowerBoundOfPriceBeforeDecimalPoint || len(ss[0]) > util.UpperBoundOfPriceBeforeDecimalPoint {
			return errors.Errorf("小数点前最少1位，至多15位")
		}
		if len(ss) > 1 {
			if len(ss[1]) > util.UpperBoundOfPriceAfterDecimalPoint {
				return errors.Errorf("小数点后至多两位")
			}
		}
	}
	if price < 0 {
		return errors.Errorf("无效价格")
	}
	return nil
}

//CheckOptionalParameterForModification 检查修改时的可选参数
func CheckOptionalParameterForModification(collection *model.CollectionDetail, req common.ModifyCollectionReq, modifyParameter *common.ModifyCollectionDetail) error {
	err := CheckPrice(req.Price)
	if err == nil {
		collection.Price = req.Price
		modifyParameter.Price = &collection.Price
	} else {
		return err
	}
	saleTime := cast.ToInt64(req.SaleTime)
	offShelfTime := cast.ToInt64(req.OffShelfTime)
	if saleTime != util.InvalidTime && offShelfTime != util.InvalidTime {
		now := time.Now().UnixMilli()
		saleInterval := saleTime - now - util.MinimumSaleTime.Milliseconds()
		interval := offShelfTime - saleTime - util.MinimumInterval.Milliseconds()
		if req.SaleTime > 0 && req.OffShelfTime > 0 && interval > 0 && saleInterval > 0 {
			collection.SaleTime = time.UnixMilli(cast.ToInt64(req.SaleTime))
			collection.OffShelfTime = time.UnixMilli(cast.ToInt64(req.OffShelfTime))
			modifyParameter.SaleTime = &collection.SaleTime
			modifyParameter.OffShelfTime = &collection.OffShelfTime
		} else {
			err = errors.Errorf("发售起始时间必须大于当前时间且发售结束时间必须晚于发售起始时间5分钟")
			return err
		}
	}
	return nil
}

func buildOneCollectionForProcessCollectionForQuery(eachCollection *model.CollectionDetail) (*common.CollectionDetail, error) {
	assetUrl, _ := util.GetAssetUrl(eachCollection.CoverUrl)
	oneCollection := common.CollectionDetail{
		CollectionIndex:    eachCollection.CollectionIndex,
		SubCollectionIndex: eachCollection.SubCollectionIndex,
		CollectionName:     eachCollection.CollectionName,
		CollectionStatus:   eachCollection.CollectionStatus,
		Supplies:           eachCollection.Supplies,
		Counters:           eachCollection.Counter,
		Favorite:           eachCollection.NumberOfFavorites,
		SaleTime:           eachCollection.SaleTime.UnixMilli(),
		OffShelfTime:       eachCollection.OffShelfTime.UnixMilli(),
		Currency:           eachCollection.Currency,
		Price:              eachCollection.Price,
		CoverUrl:           assetUrl,
	}
	if eachCollection.SubCollectionIndex != util.DefaultSubCollectionIndex {
		metaData, _ := GetMetaDataByIdentity(common.CollectionIdentity{CollectionIndex: eachCollection.CollectionIndex, SubCollectionIndex: eachCollection.SubCollectionIndex})
		metaDetail := MetaDataDetail{}
		if err := json.Unmarshal([]byte(metaData.TokenURI), &metaDetail); err != nil {
			logger.Error("ProcessCollectionForQuery error: %v", err)
			return nil, err
		}
		oneCollection.Name = metaDetail.Name
	}
	return &oneCollection, nil
}
func ProcessCollectionForQuery(collections []*model.CollectionDetail, nowTime time.Time, req common.QueryCollectionExactReq, response *common.CollectionDetailAll) error {
	//建立collectionIndex到subCollectionIndex的映射
	collectionMap := make(map[string]common.SubCollectionAll)
	//go map无序,使其有序
	collectionMapIndex := make(map[string]int)
	//下标从零开始
	index := 0
	for _, eachCollection := range collections {
		if eachCollection.CollectionStatus == util.CollectionPublished {
			//已发布未出售
			if nowTime.Before(eachCollection.SaleTime) {
				eachCollection.CollectionStatus = util.CollectionPublished
			}
			//出售中
			if nowTime.After(eachCollection.SaleTime) && nowTime.Before(eachCollection.OffShelfTime) {
				eachCollection.CollectionStatus = util.CollectionOnSale
			}
			//已结束
			if nowTime.After(eachCollection.OffShelfTime) {
				eachCollection.CollectionStatus = util.CollectionEnded
			}
			//已结束不可见--暂时也归于已结束
		}
		if req.CollectionStatus == util.DefaultCollectionStatus || eachCollection.SubCollectionIndex == util.DefaultSubCollectionIndex {
		} else {
			if eachCollection.CollectionStatus != req.CollectionStatus {
				continue
			}
		}
		oneCollection, err := buildOneCollectionForProcessCollectionForQuery(eachCollection)
		if err != nil {
			return err
		}
		if subCollection, ok := collectionMap[eachCollection.CollectionIndex]; ok {
			subCollection.SubCollections = append(subCollection.SubCollections, *oneCollection)
			subCollection.SubCollectionSize += 1
			collectionMap[eachCollection.CollectionIndex] = subCollection
		} else {
			collectionMap[eachCollection.CollectionIndex] = common.SubCollectionAll{SubCollections: []common.CollectionDetail{*oneCollection}, SubCollectionSize: 1}
			collectionMapIndex[eachCollection.CollectionIndex] = index
			index = index + 1
		}
	}
	response.Collections = make([]common.SubCollectionAll, len(collectionMapIndex))
	for _, subCollections := range collectionMap {
		if nowIndex, ok := collectionMapIndex[subCollections.SubCollections[0].CollectionIndex]; ok {
			response.Collections[nowIndex] = subCollections
		} else {
			err := errors.Errorf("collectionMap error")
			logger.Error(err.Error())
			return err
		}
	}
	response.CollectionSize = len(collectionMap)
	return nil
}
func GetCollectionIndexFromArray(collections []*model.CollectionDetail) ([]string, []common.CollectionIdentity) {
	var collection []common.CollectionIdentity
	var collectionIndex []string
	for _, oneCollection := range collections {
		collection = append(collection, common.CollectionIdentity{CollectionIndex: oneCollection.CollectionIndex, SubCollectionIndex: oneCollection.SubCollectionIndex})
		collectionIndex = append(collectionIndex, oneCollection.CollectionIndex)
	}
	return collectionIndex, collection
}
func CheckCollectionName(collectionName string) ([]*model.CollectionDetail, error) {
	lengthOfName := len(collectionName)
	//长度检测
	if lengthOfName < util.LowerBoundOfCollectionName || lengthOfName > util.UpperBoundOfCollectionName {
		logger.Error("the length of name is between 3 and 20, now is %v", lengthOfName)
		err := errors.Errorf("名称长度为3-20，现在是%v", lengthOfName)
		return nil, err
	}
	//查询是否存在以存在该集合
	collections, err := dao.GetCollectionDetailDao().GetCollectionByNameExact(collectionName)
	if err != nil {
		logger.Error(err.Error())
		err = errors.Errorf("查找集合出错")
		return nil, err
	}
	return collections, nil
}

func GetSubCollectionByStatus(userId int, collectionIndex string, collectionStatus []int) ([]*model.CollectionDetail, error) {
	queryParameter := common.QueryCollectionDetail{
		CollectionIndex:  []string{collectionIndex},
		CollectionStatus: collectionStatus,
	}
	if userId != util.InvalidNumber {
		queryParameter.UserId = &userId
	}
	subCollections, _, _, err := dao.GetCollectionDetailDao().GetCollection(&queryParameter)
	if err != nil {
		return nil, err
	}
	return subCollections, nil
}
func GetSubCollectionByCollectionIndex(userId int, collectionIndex string, collectionStatus int) ([]*model.CollectionDetail, error) {
	needMainCollection := false
	queryParameter := common.QueryCollectionDetail{
		CollectionIndex:    []string{collectionIndex},
		CollectionStatus:   []int{collectionStatus},
		NeedMainCollection: &needMainCollection,
	}
	if userId != util.InvalidNumber {
		queryParameter.UserId = &userId
	}
	subCollections, _, _, err := dao.GetCollectionDetailDao().GetCollection(&queryParameter)
	if err != nil {
		return nil, err
	}
	return subCollections, nil
}

//CheckOptionalParameterForPublish 用于在PublishCollection中校验相关参数
func CheckOptionalParameterForPublish(collection *model.CollectionDetail, req common.PublishCollectionReq) error {
	//校验价格
	err := CheckPrice(req.Price)
	if err != nil {
		err = errors.Errorf("无效价格")
		logger.Error("req.price:%v", req.Price)
		return err
	} else {
		collection.Price = req.Price
	}
	//校验时间
	saleTime := cast.ToInt64(req.SaleTime)
	offShelfTime := cast.ToInt64(req.OffShelfTime)
	now := time.Now().UnixMilli()
	interval := offShelfTime - saleTime - util.MinimumInterval.Milliseconds()
	saleInterval := saleTime - now - util.MinimumSaleTime.Milliseconds()
	if req.SaleTime > 0 && req.OffShelfTime > 0 && interval > 0 && saleInterval > 0 {
		collection.SaleTime = time.UnixMilli(cast.ToInt64(req.SaleTime))
		collection.OffShelfTime = time.UnixMilli(cast.ToInt64(req.OffShelfTime))
	} else {
		err = errors.Errorf("请输入正确的起始时间和结束时间，起始时间必须大于当前时间1分钟且结束时间至少超过起始时间5分钟")
		logger.Error(err.Error())
		return err
	}
	//校验货币
	if len(req.Currency) > 0 {
		collection.Currency = req.Currency
	}
	return nil
}
func processSubCollectionForPublishCollection(userId int, collection *model.CollectionDetail, req common.PublishCollectionReq) error {
	tempSubCollection, err := GetSubCollectionByCollectionIndex(userId, collection.CollectionIndex, util.CollectionMintCompleted)
	if err != nil {
		return err
	}
	//过滤已售罄子集合
	var soldOutCollection []*model.CollectionDetail
	var subCollection []*model.CollectionDetail
	for _, sub := range tempSubCollection {
		if sub.Counter == sub.Supplies {
			soldOutCollection = append(soldOutCollection, sub)
			continue
		}
		sub.SaleTime = collection.SaleTime
		sub.OffShelfTime = collection.OffShelfTime
		sub.Price = collection.Price
		subCollection = append(subCollection, sub)
	}
	if len(subCollection) > 0 {
		if err = WriteAllSubCollectionIntoRedis(subCollection, userId, db.RedisPool); err != nil {
			logger.Error("WriteCollectionIntoRedis error: %v", err)
			err = errors.Errorf("写入缓存失败")
			return err
		}
		collection.CollectionStatus = util.CollectionPublished
		modify := common.ModifyCollectionDetail{
			UserId:                userId,
			CollectionIndex:       collection.CollectionIndex,
			SubCollectionIndex:    util.DefaultSubCollectionIndex,
			CollectionName:        nil,
			SaleTime:              &collection.SaleTime,
			OffShelfTime:          &collection.OffShelfTime,
			Price:                 &collection.Price,
			QueryCollectionStatus: []int{util.CollectionMintCompleted},
			AfterCollectionStatus: &collection.CollectionStatus}
		if err = UpdateAllSubCollection(&modify); err != nil {
			logger.Error("UpdateAllSubCollection error: %v", err)
			return err
		}
		//重置已售罄子集合
		for _, soldOut := range soldOutCollection {
			soldOut.CollectionStatus = util.CollectionMintCompleted
			err = UpdateCollectionDetail(soldOut)
			if err != nil {
				logger.Error("UpdateCollectionDetail error: %v", err)
				return err
			}
		}
	}
	return nil
}
func publishCollectionForProcessInPublishCollection(userId int, collection *model.CollectionDetail, req common.PublishCollectionReq) error {
	//校验价格等参数
	if err := CheckOptionalParameterForPublish(collection, req); err != nil {
		return err
	}
	if collection.SubCollectionIndex != util.DefaultSubCollectionIndex {
		if collection.Counter == collection.Supplies {
			err := errors.Errorf("已售罄，不可发布")
			return err
		}
		if err := WriteSubCollectionIntoRedis(collection, userId, db.RedisPool); err != nil {
			err = errors.Errorf("写入缓存失败")
			return err
		}
		collection.CollectionStatus = util.CollectionPublished
		if err := UpdateCollectionDetail(collection); err != nil {
			logger.Error("UpdateCollectionDetail error: %v", err)
			return err
		}
	} else {
		err := processSubCollectionForPublishCollection(userId, collection, req)
		if err != nil {
			return err
		}
	}
	return nil
}
func ProcessInPublishCollection(userId int, collection *model.CollectionDetail, req common.PublishCollectionReq) error {
	//发布集合时写入redis
	var subCollection []*model.CollectionDetail
	var err error
	if collection.CollectionStatus == util.CollectionMintCompleted {
		if err = publishCollectionForProcessInPublishCollection(userId, collection, req); err != nil {
			return err
		}
	} else if collection.CollectionStatus == util.CollectionPublished {
		//取消发布集合时删除redis
		if collection.SubCollectionIndex != util.DefaultSubCollectionIndex {
			if err = DeleteSubCollectionFromRedis(collection, db.RedisPool); err != nil {
				logger.Error("DeleteCollectionFromRedis error: %v", err)
				err = errors.Errorf("删除缓存失败")
				return err
			}
			collection.CollectionStatus = util.CollectionMintCompleted
			err = UpdateCollectionDetail(collection)
			if err != nil {
				logger.Error("UpdateCollectionDetail error: %v", err)
				return err
			}
		} else {
			subCollection, err = GetSubCollectionByCollectionIndex(userId, collection.CollectionIndex, util.CollectionPublished)
			if err != nil {
				return err
			}
			if err = DeleteAllSubCollectionFromRedis(subCollection, db.RedisPool); err != nil {
				logger.Error("WriteCollectionIntoRedis error: %v", err)
				err = errors.Errorf("删除缓存失败")
				return err
			}
			collection.CollectionStatus = util.CollectionMintCompleted
			modify := common.ModifyCollectionDetail{UserId: userId, CollectionIndex: collection.CollectionIndex, SubCollectionIndex: util.DefaultSubCollectionIndex, QueryCollectionStatus: []int{util.CollectionPublished}, AfterCollectionStatus: &collection.CollectionStatus}
			err = UpdateAllSubCollection(&modify)
			if err != nil {
				logger.Error("UpdateAllSubCollection error: %v", err)
				return err
			}
		}
	} else {
		//其他状态不可发布
		err = errors.Errorf("该状态下不可发布")
		logger.Error("cannot be publish in the status")
		return err
	}
	return nil
}
